﻿// Copyright 2008 Chris Varley (http://www.contractdriven.net/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.using System;

using System;
using System.Collections.Generic;
using ContractDriven.CommonAssertions;

namespace ContractDriven
{
	/// <summary>
	/// A factory for Common Assertions.
	/// </summary>
	public static class Assert
	{
		/// <summary>
		/// Guarantee that a specified object is not null.
		/// </summary>
		/// <param name="target">The object to check</param>
		/// <returns>A NotNullAssertion for the specified case</returns>
		public static IAssertion IsNotNull(object target)
		{
			return new NotNullAssertion(target);
		}

		/// <summary>
		/// Guarantee that a specified string is not null or empty.
		/// </summary>
		/// <param name="target">The string to check</param>
		/// <returns>A StringNotNullOrEmptyAssertion for the specified case</returns>
        public static IAssertion IsNotNullOrEmpty(string target)
		{
			return new EmptyStringAssertion(target);
		}
		
		/// <summary>
		/// <para>Guarantee that a specified item false within a specified range.</para>
		/// <para>Note: All IComparible parameters must be of the same type.</para>
		/// </summary>
		/// <param name="target">The IComparible to check.</param>
		/// <param name="min">The minimum value of the allowed range.</param>
		/// <param name="max">The maximum value of the allowed range.</param>
		/// <returns></returns>
        public static IAssertion IsInRange(IComparable target, IComparable min, IComparable max)
		{
			return new RangeAssertion(target, min, max);
		}

		/// <summary>
		/// Guaranteee that a specified string is of a particular length
		/// </summary>
		/// <param name="target">The string to check</param>
		/// <param name="min">The minimum length of the string</param>
		/// <param name="max">The maximum length of the string</param>
		/// <returns></returns>
        public static IAssertion IsLengthInRange(string target, int min, int max)
		{
			return new StringLengthAssertion(target, min, max);
        }
        #region Contains / Not Contains Assertions
        /// <summary>
        /// Verifies that a string contains a given sub-string, using the current culture.
        /// </summary>
        /// <param name="expectedSubString">The sub-string expected to be in the string</param>
        /// <param name="actualString">The string to be inspected</param>
        public static IAssertion Contains(string expectedSubString, string actualString)
        {
            return new StringContainsAssertion(expectedSubString, actualString, StringComparison.CurrentCulture);
        }

       
        /// <summary>
        /// Verifies that a string contains a given sub-string, using the given comparison type.
        /// </summary>
        /// <param name="expectedSubString">The sub-string expected to be in the string</param>
        /// <param name="actualString">The string to be inspected</param>
        /// <param name="comparisonType">The type of string comparison to perform</param>
        public static IAssertion Contains(string expectedSubString, string actualString, StringComparison stringComparison)
        {
            return new StringContainsAssertion(expectedSubString, actualString, stringComparison);
        }


        /// <summary>
        /// Verifies that a string does not contains a given sub-string, using the current culture.
        /// </summary>
        /// <param name="expectedSubString">The sub-string expected to be in the string</param>
        /// <param name="actualString">The string to be inspected</param>
        public static IAssertion NotContains(string expectionSubString, string actualString)
        {
            return new StringNotContainsAssertion(expectionSubString, actualString, StringComparison.CurrentCulture);
        }

        /// <summary>
        /// Verifies that a string does not contains a given sub-string, using the given comparison type.
        /// </summary>
        /// <param name="expectedSubString">The sub-string expected to be in the string</param>
        /// <param name="actualString">The string to be inspected</param>
        /// <param name="comparisonType">The type of string comparison to perform</param>
        public static IAssertion NotContains(string expectionSubString, string actualString, StringComparison stringComparison)
        {
            return new StringNotContainsAssertion(expectionSubString, actualString, stringComparison);
        }

        /// <summary>
        /// Verifies that a collection contains a given object, using a comparer.
        /// </summary>
        /// <typeparam name="T">The type of the object to be verified</typeparam>
        /// <param name="expected">The object expected to be in the collection</param>
        /// <param name="collection">The collection to be inspected</param>
        /// <param name="comparer">The comparer used to equate objects in the collection with the expected object</param>
        public static IAssertion Contains<T>(T expected, IEnumerable<T> collection, IComparer<T> comparer)
        {
            return new CollectionContainsAssertion<T>(expected, collection, comparer);
        }

        /// <summary>
        /// Verifies that a collection contains a given object.
        /// </summary>
        /// <typeparam name="T">The type of the object to be verified</typeparam>
        /// <param name="expected">The object expected to be in the collection</param>
        /// <param name="collection">The collection to be inspected</param>
        public static IAssertion Contains<T>(T expected, IEnumerable<T> collection)
        {
            return new CollectionContainsAssertion<T>(expected, collection);
        }

        /// <summary>
        /// Verifies that a collection does not contain a given object.
        /// </summary>
        /// <typeparam name="T">The type of the object to be compared</typeparam>
        /// <param name="expected">The object that is expected not to be in the collection</param>
        /// <param name="collection">The collection to be inspected</param>
        /// <param name="comparer">The comparer used to equate objects in the collection with the expected object</param>
        public static IAssertion NotContains<T>(T expected, IEnumerable<T> collection, IComparer<T> comparer)
        {
            return new CollectionNotContainsAssertion<T>(expected, collection, comparer);
        }

        /// <summary>
        /// Verifies that a collection does not contain a given object.
        /// </summary>
        /// <typeparam name="T">The type of the object to be compared</typeparam>
        /// <param name="expected">The object that is expected not to be in the collection</param>
        /// <param name="collection">The collection to be inspected</param>
        public static IAssertion NotContains<T>(T expected, IEnumerable<T> collection)
        {
            return new CollectionNotContainsAssertion<T>(expected, collection);
        }
        #endregion
        #region True/False Assertions
        /// <summary>
        /// Verifies that an expression is true.
        /// </summary>
        /// <param name="condition">The condition to be inspected</param>
        public static IAssertion True(bool condition)
        {
            return new TrueAssertion(condition);
        }



        /// <summary>
        /// Verifies that an expression is false.
        /// </summary>
        /// <param name="condition">The condition to be inspected</param>
        public static IAssertion False(bool condition)
        {
            return new FalseAssertion(condition);
        }

        #endregion
        #region Equal/Not Equal Assertions
        /// <summary>
        /// Verifies that two objects are equal, using a default comparer.
        /// </summary>
        /// <typeparam name="T">The type of the objects to be compared</typeparam>
        /// <param name="expected">The expected value</param>
        /// <param name="actual">The value to be compared against</param>
        public static IAssertion Equal<T>(T expected, T actual)
        {
            return new EqualAssertion<T>(expected, actual);
        }

        /// <summary>
        /// Verifies that two objects are equal, using a custom comparer.
        /// </summary>
        /// <typeparam name="T">The type of the objects to be compared</typeparam>
        /// <param name="expected">The expected value</param>
        /// <param name="actual">The value to be compared against</param>
        /// <param name="comparer">The comparer used to compare the two objects</param>
        public static IAssertion Equal<T>(T expected, T actual, IComparer<T> comparer)
        {
            return new EqualAssertion<T>(expected, actual, comparer);
        }

        /// <summary>
        /// Verifies that two objects are not equal, using a default comparer.
        /// </summary>
        /// <typeparam name="T">The type of the objects to be compared</typeparam>
        /// <param name="expected">The expected object</param>
        /// <param name="actual">The actual object</param>
        public static IAssertion NotEqual<T>(T expected, T actual)
        {
            return new NotEqualAssertion<T>(expected, actual);
        }

        /// <summary>
        /// Verifies that two objects are not equal, using a custom comparer.
        /// </summary>
        /// <typeparam name="T">The type of the objects to be compared</typeparam>
        /// <param name="expected">The expected object</param>
        /// <param name="actual">The actual object</param>
        /// <param name="comparer">The comparer used to examine the objects</param>
        public static IAssertion NotEqual<T>(T expected, T actual, IComparer<T> comparer)
        {
            return new NotEqualAssertion<T>(expected, actual, comparer);
        }
        #endregion
        #region Same Assertion
        /// <summary>
        /// Verifies that two objects are the same instance.
        /// </summary>
        /// <param name="expected">The expected object instance</param>
        /// <param name="actual">The actual object instance</param>       
        public static IAssertion Same(object expected, object actual)
        {
            return new SameAssertion(expected, actual);
        }

        /// <summary>
        /// Verifies that two objects are not the same instance.
        /// </summary>
        /// <param name="expected">The expected object instance</param>
        /// <param name="actual">The actual object instance</param>        
        public static IAssertion NotSame(object expected,object actual)
        {
            return new NotSameAssertion(expected, actual);
        }
        #endregion
        #region Type Assertion
        /// <summary>
        /// Verifies that an object is exactly the given type (and not a derived type).
        /// </summary>
        /// <typeparam name="T">The type the object should be</typeparam>
        /// <param name="object">The object to be evaluated</param>        
        public static IAssertion IsType<T>(object @object)
        {
            return new IsTypeAssertion<T>(@object);
        }

        /// <summary>
        /// Verifies that an object is not exactly the given type.
        /// </summary>
        /// <typeparam name="T">The type the object should not be</typeparam>
        /// <param name="object">The object to be evaluated</param>
        public static IAssertion IsNotType<T>(object @object)
        {
            return new IsNotTypeAssertion<T>(@object);
        }
        #endregion
        #region Throws Assertion
        /// <summary>
        /// Verifies that the exact exception is thrown (and not a derived exception type).
        /// </summary>
        /// <typeparam name="T">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        public static IAssertion Throws<T>(ThrowsDelegate testCode)
            where T : Exception
        {
            return new ThrowsAssertion<T>(testCode);
        }

        /// <summary>
        /// Verifies that a block of code does not throw any exceptions.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        public static IAssertion DoesNotThrows(ThrowsDelegate testCode)
        {
            return new DoesNotThrowAssertion(testCode);
        }


        #endregion

    }
}
